#include "driver_DHT11.h"
#include "gpio.h"
#include "tim.h"
#include "driver_printf.h"


#define	IO_0     HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET)
#define IO_1     HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET)

static uint8_t data[5];

/*

方法	    精度	最大延时	资源占用	适用场景
DWT	        最高	~59s	    无	        高精度短延时
硬件定时器	高	    65.535ms	1个TIM	    中等长度精确延时
SysTick	    中等	16.7ms	    共享	    系统集成简单应用

*/
void DHT11_Delay_us(uint16_t us)
{
	// tim方法
    __HAL_TIM_SET_COUNTER(&htim3, 0);
	__HAL_TIM_ENABLE(&htim3);
	while (__HAL_TIM_GET_COUNTER(&htim3) < us);
	__HAL_TIM_DISABLE(&htim3);

	// DWT方法
//	// 启用DWT功能
//    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; 
//    // 重置CYCCNT计数器
//    DWT->CYCCNT = 0;
//    // 启用CYCCNT计数器
//    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
//	
//	uint32_t start = DWT->CYCCNT;
//    uint32_t cycles = us * (SystemCoreClock / 1000000);
//    
//    while((DWT->CYCCNT - start) < cycles);
}

HAL_StatusTypeDef DHT11_Wait_Level(uint16_t level)
{
    uint32_t timeout = 200;
	
    while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) != level) {
		DHT11_Delay_us(1);
        if(0 == --timeout){
			printf("DHT11_Wait_Level timeout!\r\n");
			return HAL_TIMEOUT;
		}
    }
	
    return HAL_OK;
}

uint8_t* DHT11_Get()
{
    // 1.主机发送开始信号
    IO_0;
    DHT11_Delay_us(18500);  // >18ms
    IO_1;
	DHT11_Delay_us(30);  // 20~40um
    
    // 2.主机切换为输入模式
    GPIO_InitTypeDef gpio;
    gpio.Pin = GPIO_PIN_1;
	gpio.Mode = GPIO_MODE_INPUT;
	gpio.Pull = GPIO_PULLUP;
	gpio.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOA, &gpio);
    
    // 3.主机等待DHT11响应
	if(DHT11_Wait_Level(0) != HAL_OK){  // 80um
		printf("1\r\n");
		return 0;
	}
	if(DHT11_Wait_Level(1) != HAL_OK){  // 80um
		printf("2\r\n");
		return 0;
	}
	if(DHT11_Wait_Level(0) != HAL_OK){
		printf("2.1\r\n");
		return 0;
	}

    // 4.DHT11开始发送数据，主机读取40位数据, 湿度高8位 + 湿度低8位 + 温度高8位 + 温度低8位 + 校验位
    for(uint8_t i = 0; i < 5; ++i) {
        for(uint8_t j = 0; j < 8; ++j) {
			if(DHT11_Wait_Level(1) != HAL_OK){
				printf("3\r\n");
				return 0;
			}
            DHT11_Delay_us(50);
			
            data[i] <<= 1;
			if(1 == HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1)){
				data[i] |= 1;
			}

            if(DHT11_Wait_Level(0) != HAL_OK){
				printf("4\r\n");
				return 0;
			}
        }
    }
    // 数据发送完毕，DHT11拉低50um，然后释放
	if(DHT11_Wait_Level(1) != HAL_OK){
		printf("5\r\n");
		return 0;
	}
	
    // 5.主机恢复输出模式
    gpio.Mode = GPIO_MODE_OUTPUT_OD;
    HAL_GPIO_Init(GPIOA, &gpio);
    
    // 校验数据
    if((data[0] + data[1] + data[2] + data[3]) == data[4]) {
//		printf("right: %d ",data[0]);
//		printf("%d ",data[1]);
//		printf("%d ",data[2]);
//		printf("%d ",data[3]);
//		printf("%d",data[4]);
        return data;
    }
	printf("wrong: %d ",data[0]);
	printf("%d ",data[1]);
	printf("%d ",data[2]);
	printf("%d ",data[3]);
	printf("%d",data[4]);
    return 0;
	
	// 两次采样间隔 ≥ 1秒
}
